{The unit SImulate controls the form SimulateForm which allows the user to
set conditions for a simulated titration, perform it, and save or display
the results.  }

unit Simulate;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, StdCtrls, TitrDefs, Buttons, Grids, ExtCtrls, TeEngine,
  Series, TeeProcs, Chart, Solver, Editor, Math;

type
  TSimulateForm = class(TForm)
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    New1: TMenuItem;
    Save1: TMenuItem;
    Exit1: TMenuItem;
    Editing: TMenuItem;
    EditSystem: TMenuItem;
    EditParams: TMenuItem;
    Titrate: TMenuItem;
    MenuHelp: TMenuItem;
    About1: TMenuItem;
    Topics: TMenuItem;
    MenuExit: TMenuItem;
    SimulateSaveDialog: TSaveDialog;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Label7: TLabel;
    TitleEdit: TEdit;
    CationList: TComboBox;
    DefLabel: TStaticText;
    AnionList: TComboBox;
    V0Edit: TEdit;
    SimulateBtn: TButton;
    TiDataGrid: TStringGrid;
    DeltaVolEdit: TEdit;
    SimuPtsEdit: TEdit;
    VFinalEdit: TEdit;
    AnionConcEdit: TEdit;
    CationConcEdit: TEdit;
    Label8: TLabel;
    Label9: TLabel;
    Label10: TLabel;
    Label11: TLabel;
    Bevel1: TBevel;
    Label12: TLabel;
    Label13: TLabel;
    Label14: TLabel;
    Label15: TLabel;
    Label16: TLabel;
    SimulGraph: TChart;
    Series1: TLineSeries;
    Series2: TLineSeries;
    Series3: TLineSeries;
    Series4: TLineSeries;
    Series5: TLineSeries;
    YSelect: TComboBox;
    Y2Select: TComboBox;
    Y3Select: TComboBox;
    Y4Select: TComboBox;
    Y5Select: TComboBox;
    Label17: TLabel;
    Label18: TLabel;
    Label19: TLabel;
    Bevel2: TBevel;
    LogMol: TRadioGroup;

    Procedure DefaultSimulation;
    Procedure WriteScreen;
    procedure FormActivate(Sender: TObject);
    procedure TitleEditExit(Sender: TObject);
    procedure CationListExit(Sender: TObject);
    procedure CationConcEditExit(Sender: TObject);
    procedure AnionListExit(Sender: TObject);
    procedure AnionConcEditExit(Sender: TObject);
    procedure SimuPtsEditExit(Sender: TObject);
    procedure DeltaVolEditExit(Sender: TObject);
    procedure V0EditExit(Sender: TObject);
    Procedure WriteSimResults;
    Procedure ClearResults;
    Procedure SaveResults;
    Procedure Save1Click(Sender: TObject);
    Procedure Exit1Click(Sender: TObject);
    Procedure EditSystemClick(Sender: TObject);
    Procedure EditParamsClick(Sender: TObject);

    procedure PlotY1(Conc : integer);
    procedure PlotY2(Conc : integer);
    procedure PlotY3(Conc : integer);
    procedure PlotY4(Conc : integer);
    procedure PlotY5(Conc : integer);
    Procedure PlotAll;
    procedure YSelectChange(Sender: TObject);
    procedure Y2SelectChange(Sender: TObject);
    procedure Y3SelectChange(Sender: TObject);
    procedure Y4SelectChange(Sender: TObject);
    procedure Y5SelectChange(Sender: TObject);

    procedure New1Click(Sender: TObject);
    procedure MenuExitClick(Sender: TObject);
    procedure About1Click(Sender: TObject);
    procedure TopicsClick(Sender: TObject);
    procedure TitrateBtnClick(Sender: TObject);
    Procedure LinearPlot;
    procedure LogMolExit(Sender: TObject);


  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  SimulateForm: TSimulateForm;

implementation

uses ParamEdit, TitrHelp;

{$R *.dfm}

{DefaultSimulation sets the simulation control parameters to the default values}

Procedure TSimulateForm.DefaultSimulation;

Var i, com, spe : integer;

begin
  SimuPts := 0;                 { no points to be titrated }
  V0 := 0;                      { Initial volume is 0 mLs }
  DeltaVol  := 0;               { increment set to 0 mLs}
  VolAdded[1] := 0;             { for display only}
  VFinal := 0;                  { are set to zero }
  SimulationDone := False;       { titration not calculated}
  fillchar(SimuHead,sizeof(SimuHead),0);   {no title }
  Vfinal   := 0;                 { final titrant volume in titration}
  TitrCation := 0;               { # of first titrated component (cation)}
  TitrAnion :=0;                 { # of second titrated component (anion)}
  CationConc := 0;               { molar conc. of cation }
  AnionConc :=0;                 { molar con. of anion}
  LogMolar := 1;                 { Log scale on graph }

  {Place options in to the series selection combo boxes, 0 = no selection}

    YSelect.Items.Clear;
    YSelect.Items.Add('None selected');
    For com := 1 to S.NComp do
       i := Yselect.Items.add(S.Comps[com].Name);
    For spe := 1 to S.NSpec do
       i := YSelect.Items.add(S.Specs[spe].Name);

    YSelect.ItemIndex := 0;
    Y2Select.Items := YSelect.Items;   Y2Select.ItemIndex := 0;
    Y3Select.Items := YSelect.Items;   Y3Select.ItemIndex := 0;
    Y4Select.Items := YSelect.Items;   Y4Select.ItemIndex := 0;
    Y5Select.Items := YSelect.Items;   Y5Select.ItemIndex := 0;
 end;


{WriteScreen writes in values for the various editing controls on the titration}
{screen (SimulateForm)}

Procedure TSimulateForm.WriteScreen;
Var com, i : integer;

begin

   {Write in the title of the titration data, if any}
   TitleEdit.Text := TitrHead.Title;
   DefLabel.Caption := 'Definition: ' + S.Head.Title;

   {Write the 'total-known' component names into the dropdown lists CationList}
   {and AnionList}
   CationList.Items.Clear;                               {First clear the lists}
   AnionList.Items.Clear;
   CationList.Items.Add('None selected');
   AnionList.Items.Add('None selected');
   For com := 1 to S.NComp do begin
       i := CationList.Items.add(S.Comps[com].Name);
       i := AnionList.Items.add(S.comps[com].Name);
     end;


   {Write in the text for the editing controls}
   V0Edit.Text := FloatToStrF(V0, ffFixed, 5, 3);
   DeltaVolEdit.Text := FloatToStrF(DeltaVol, ffFixed, 5, 3);
   SimuPtsEdit.Text := IntToStr(SimuPts);
   VFinalEdit.Text := FloatToStrF(VFinal, ffFixed, 8, 3);
   CationConcEdit.Text := FloatToStrF(CationConc, ffExponent, 4, 3);
   AnionConcEdit.Text := FloatToStrF(AnionConc, ffExponent, 4, 3);
   CationList.ItemIndex := TitrCation;
   AnionList.ItemIndex := TitrAnion;

   LogMol.ItemIndex := LogMolar;

end;

{Whenever the form is activated, clear the titration settings and results and}
{display a blank form}

procedure TSimulateForm.FormActivate(Sender: TObject);
begin
   DefaultSimulation;
   WriteScreen;
   ClearResults;
end;

{GetAbMax return the largest absolute value in the first N elements of vector X}

Function GetAbMax(Var X : DataArray; N : integer) : double;
Var TempMax : double;
    i : integer;

begin
   TempMax := 0;
   For i := 0 to N do
      if (abs(X[i]) > TempMax) then
          TempMax := abs(X[i]);
   GetAbMax := TempMax;
end;


{TitleEditExit records the user's choice for a title for this simulation }
{in the header }

procedure TSimulateForm.TitleEditExit(Sender: TObject);
begin
    SimuHead.Title := TitleEdit.Text;
end;

{CationListExit is invoked whenever the drop-down Cation list of components }
{has been exited- presumably after the user has changed the component to }
{titrate.  The new component choice is recorded in TitrCation.}

procedure TSimulateForm.CationListExit(Sender: TObject);
begin
   TitrCation := CationList.ItemIndex;           {Record new titrated component}
   SimulationDOne := False;                       {Clear any preceding results}
   ClearResults;
end;

{CationConcEditExit handles the input for the concentration of the titrant }
{ Cation, which can range from 1e-20 (ridiculously small) to 50 M}

procedure TSimulateForm.CationConcEditExit(Sender: TObject);
begin
   CationConcEdit.Text := WriteRealEditExp(CationConcEdit.Text, CationConc, -50, 50);
   SimulationDOne := False;
   ClearResults;
end;

{AnionListExit is invoked whenever the drop-down anion list of components }
{has been exited- presumably after the user has changed the component to }
{titrate.  The new component choice is recorded in TitrAniona.}

procedure TSimulateForm.AnionListExit(Sender: TObject);
begin
   TitrAnion := AnionList.ItemIndex;            {Record new titrated component}
   SimulationDOne := False;                       {Clear any preceding results}
   ClearResults;
end;

{AnionConcEditExit handles the input for the concentration of the titrant }
{ Anion, which can range from 1e-20 (ridiculously small) to 50 M}

procedure TSimulateForm.AnionConcEditExit(Sender: TObject);
begin
   AnionConcEdit.Text := WriteRealEditExp(AnionConcEdit.Text, AnionConc, -50, 50);
   SimulationDOne := False;
   ClearResults;
end;

{ PointsEditExit gets the number of titration data points, checks for valid}
{ values (at least 3, not more than 201), then calculates the new FinalPt }
{ and displays the text}

procedure TSimulateForm.SimuPtsEditExit(Sender: TObject);
begin
    SimuPtsEdit.Text := WriteIntEdit(SimuPtsEdit.Text, SimuPts, 3, NDataPts);
    VFinal := DeltaVol * (SimuPts-1);
    VFinalEdit.Text :=  FloatToStrF(VFinal*1000, ffFixed, 8, 3);
    SimulationDOne := False;
    ClearResults;
end;

{ IncrEditExit gets the new titration increment in mLs, checks for valid}
{ values (0.001 to 100), then calculates the new FinalPt and displays the text}
{ Note that DeltaVol is in L}

procedure TSimulateForm.DeltaVolEditExit(Sender: TObject);

Var    DeltaVmls : double;          {Volume increment in mls}

begin
   DeltaVmLs := DeltaVol * 1000;        {Convert volume to mLs}
   DeltaVolEdit.Text := WriteRealEditFix(DeltaVolEdit.Text, DeltaVmLs, 1e-3, 100);
   DeltaVol := DeltaVmLs / 1000;        {Convert volume back to liters}
   VFinal := DeltaVol * (SimuPts-1);
   If (SimuPts > 0) then
       VFinalEdit.Text :=  FloatToStrF(VFinal * 1000, ffFixed, 8, 3);
   SimulationDOne := False;
   ClearResults;
end;

{V0EditExit gets the volume of the solution to be titrated in mLs}
{Note that V0 is in liters}

procedure TSimulateForm.V0EditExit(Sender: TObject);

Var    V0mls : double;          {Initial Volume in mls}

begin
   V0mLs := V0 * 1000;          {convert to mLs}
   V0Edit.Text := WriteRealEditFix(V0Edit.Text, V0mLs, 1e-6, 1e4);
   V0 := V0mLs / 1000;          {convert back to liters}
   SimulationDOne := False;
   ClearResults;
end;

{The procedure WriteSimResults writes the current titration results from }
{arrays XData and YData into the string grid TiDataGrid for user inspection}

Procedure TSimulateForm.WriteSimResults;

Var x, com, spe : integer;                     {counts columns and rows}
    i     : integer;

begin
   {First resize the results grid}
   TiDataGrid.RowCount := SimuPts + 1;
   TiDataGrid.ColCount := S.NSpec + S.Ncomp + 1;
   TiDataGrid.FixedCols := 1;
   TiDatagrid.FixedRows := 1;

   {Next write the header information in the top row}

   SimulateForm.TiDataGrid.Cells[0, 0] := 'Volume (mls)';

   For com := 1 to S.NComp do
       SimulateForm.TiDataGrid.Cells[com, 0] := S.Comps[com].Name;

   For spe := 1 to S.NSpec do
       SimulateForm.TiDataGrid.Cells[spe + S.NComp, 0] := S.Specs[spe].Name;

   {Now write the contents of Xdata and YData to the grid}
   For x:= 1 to SimuPts do begin
     SimulateForm.TiDataGrid.Cells[0, x] :=
          FloatToStrF(VolAdded[x]*1000, ffFixed, 4,3);
     For com := 1 to (S.NComp + S.NSpec) do
        SimulateForm.TiDataGrid.Cells[com, x] :=
           FloatToStrF(Ydata[com, x], ffExponent, 4,3);

    end;

    {Now clear the results graph of data}
    {Initialize the graph axes}
    SimulGraph.LeftAxis.Automatic := True;
    SimulGraph.BottomAxis.Title.Caption := 'Volume (mls)';

 {Finally, plot the log free concentration of the titrated component }
 {and indicate that this is the first plotted variable in the combo-box YSelect}

    Series1.Title := YSelect.Items[TitrCation];
    YSelect.ItemIndex := TitrCation;
    LogMolar := 1;
    LogMol.ItemIndex := 1;
    PlotY1(TitrCation);
    Series2.Clear;  Series3.Clear; Series4.Clear;  Series5.Clear;

end;                                       {End of WriteSimResults}

{ClearResults is used to remove results of previous calculations when a }
{titration parameter has changed }

Procedure TSimulateForm.ClearResults;

begin
  SimulationDone := False;
  {Size the data grid to a single cell and empty it}
  SimulateForm.TiDataGrid.RowCount := 1;
  SimulateForm.TiDataGrid.ColCount := 1;
  SimulateForm.TiDataGrid.Cells[0, 0] := '';
  {SimulateForm.SimulGraph.BottomAxis.Title.Caption := ''; }

  {Clear out the data series for plotting and their titles}

  Series1.Clear; Series1.Title := ''; YSelect.ItemIndex := 0;
  Series2.Clear; Series2.Title := ''; Y2Select.ItemIndex := 0;
  Series3.Clear; Series3.Title := ''; Y3Select.ItemIndex := 0;
  Series4.Clear; Series4.Title := ''; Y4Select.ItemIndex := 0;
  Series5.Clear; Series5.Title := ''; Y5Select.ItemIndex := 0;

end;                               {End of ClearResults}

{TitrateBtnClick allows the user to perform a titration using previously }
{selected conditions.  First the conditions are checked to be sure that a }
{titration can be run,   }

procedure TSimulateForm.TitrateBtnClick(Sender: TObject);

Var i : integer;                   {counter variable for additions/increments}
    TotalVol : double;             {Volume of initial solution + added titrant}

begin

    {First check to see if titration conditions are set}
    If ((SimuPts < 3) or (TitrCation <1) or (not (V0 > 0)) or (DeltaVol = 0)) then begin
        ShowMessage('You must define titration conditions before calculating.');
        Exit;
      end;

    ClearResults;
    {Now fill the arrays VolAdded and XPlot with added titrant volume}
    SimulationDone := False;
    For i := 1 to SimuPts do begin
        VolAdded[i] := (i-1) * DeltaVol;
        XPlot[i] := VolAdded[i] * 1000;
       end;

   OriginalSystem := S;              {Save the current system definition}

   {and finally solve using the TitrateSolve routine}
    if (Not TitrateSolve) then begin
       If (PhaseViol) then
         Showmessage('Phase rule violation- results invalid.');
       If (TooMany) then
         Showmessage('Iteration did not converge- results may be incorrect.');
       S := OriginalSystem;          {Restore the original data definition}
       Exit;
     end;
     {else  Showmessage('Titration simulated.');  }

    WriteSimResults;

    SimulationDone := True;
    S := OriginalSystem;              {Restore the original data definition}
end;                                  {End of TitrateBtnClick }

{Exiting or closing the form returns the user to the system definition screen }

procedure TSimulateForm.Exit1Click(Sender: TObject);
begin
    SimulateForm.Close;
end;

{Procedure SaveResults writes the titration results in XData and YData to }
{an ASCII file suitable for reading by a spreadsheet }

Procedure TSimulateForm.SaveResults;

 Var
    F : TextFile;                     {ASCII text file}
    FileName : String;                {File name to save}
    SaveData : Boolean;               {Was a filename given by user?}
    Ypts     : integer;
    x, y     : integer;               {text line counter}
    com, spe : integer;               {component and species counters}
    dummy    : string;

begin
  If (not SimulationDone) then begin
   ShowMessage('You must have simulated a titration with current parameters to save a file.');
   Exit;
  end;

  SaveData := SimulateSaveDialog.Execute;      {get name of file to be saved}

  If SaveData then begin                   {if a name is chosen then...}

    If (ofExtensionDifferent in SimulateSaveDialog.Options) then begin
        ShowMessage('Please save as a txt file.');
        Exit;
       end;

    FileName := SimulateSaveDialog.Filename;
    AssignFile(F, FileName);          { Open file for writing}
         {$I-}

    ReWrite(F);                       { start at the beginning of the file}

  {Give the names of both the system definition used to generate the titration}
  {and the results data set, if any}

    Writeln(F, '"System Definition: ' + S.head.title);
    Writeln(F, '"Titration simulation: ' + Simuhead.title);

  {Next write the names of the variables calculated }

    Write(F, 'Volume ');
    For com := 1 to S.NComp do
        Write(F, S.Comps[com].Name,' ');
    For spe := 1 to S.NSpec do
        Write(F, S.Specs[spe].name, ' ');
    Writeln(F);

    {Finally write the actual data, one line for each x value}

    YPts := S.NComp + S.NSpec;

    For x := 1 to SimuPts do begin
       str(VolAdded[x]:14, dummy);
       dummy := trimleft(dummy);
       Write(F, dummy, ' ');
       For y := 1 to YPts do
         Write(F, YData[y, x]:12, ' ');
       WriteLn(F);
      end;

     CloseFile(F);
   end;                           {end if SaveData}

end;                              {end of procedure SaveResults}

{Menu item File/Save should write the current titration data to a text }
{file with extension .txt, readable by Excel or similar program}

procedure TSimulateForm.Save1Click(Sender: TObject);
begin
  SaveResults;
end;

{To edit the system definition, the current window is closed, returning control
to the main program window}

procedure TSimulateForm.EditSystemClick(Sender: TObject);
begin
   SimulateForm.Close;
end;

{To edit system parameters, open ParamForm (also used from main window)}

procedure TSimulateForm.EditParamsClick(Sender: TObject);
begin
   Paramform.Showmodal;
end;

 { The following set of routines (YselectChange, Y2SelectChange, etc.) }
{ is highly repetitive and should be condensed.  These routines permit the user
{ to select dependent variables (concentrations) to be plotted}

procedure TSimulateForm.PlotY1(Conc : integer);

Var  x : integer;                   {counter}

begin
 Series1.Clear;                     {clear the plot}
 If (LogMolar = 1) then begin
   for X := 1 to SimuPts do
       If (YData[Conc, X] > 0) then
         Series1.AddXY(XPlot[X], ln(YData[Conc, X])/LogConvr);
       end;                           {end If LogMolar...}
 If (LogMolar = 0) then begin
      for X := 1 to SimuPts do
          Series1.AddXY(XPlot[X], YData[Conc, X]*Power(10, 3 * YOrd));
     end;

end;

procedure TSimulateForm.PlotY2(Conc : integer);

Var  x : integer;                   {counter}

begin
 Series2.Clear;                     {clear the plot}
 If (LogMolar = 1) then begin
   for X := 1 to SimuPts do
       If (YData[Conc, X] > 0) then
         Series2.AddXY(XPlot[X], ln(YData[Conc, X])/LogConvr);
       end;                           {end If LogMolar...}
 If (LogMolar = 0) then
      for X := 1 to SimuPts do
           Series2.AddXY(XPlot[X], YData[Conc, X]*Power(10, 3 * YOrd));
end;

 procedure TSimulateForm.PlotY3(Conc : integer);

Var  x : integer;                   {counter}

begin
 Series3.Clear;                     {clear the plot}
 If (LogMolar = 1) then begin
   for X := 1 to SimuPts do
       If (YData[Conc, X] > 0) then
         Series3.AddXY(XPlot[X], ln(YData[Conc, X])/LogConvr);
       end;                           {end If LogMolar...}
 If (LogMolar = 0) then
      for X := 1 to SimuPts do
           Series3.AddXY(XPlot[X], YData[Conc, X]*Power(10, 3 * YOrd));
end;

procedure TSimulateForm.PlotY4(Conc : integer);

Var  x : integer;                   {counter}

begin
 Series4.Clear;                     {clear the plot}
 If (LogMolar = 1) then begin
   for X := 1 to SimuPts do
       If (YData[Conc, X] > 0) then
         Series4.AddXY(XPlot[X], ln(YData[Conc, X])/LogConvr);
       end;                           {end If LogMolar...}
 If (LogMolar = 0) then
      for X := 1 to SimuPts do
           Series4.AddXY(XPlot[X], YData[Conc, X]*Power(10, 3 * YOrd));
end;

procedure TSimulateForm.PlotY5(Conc : integer);

Var  x : integer;                   {counter}

begin
 Series5.Clear;                     {clear the plot}
 If (LogMolar = 1) then begin
   for X := 1 to SimuPts do
       If (YData[Conc, X] > 0) then
         Series5.AddXY(XPlot[X], ln(YData[Conc, X])/LogConvr);
       end;
                         {end If LogMolar...}
 If (LogMolar = 0) then
      for X := 1 to SimuPts do
           Series5.AddXY(XPlot[X], YData[Conc, X]*Power(10, 3 * YOrd));
end;

Procedure TSimulateForm.PlotAll;

begin
     If (YSelect.ItemIndex > 0) then
        PlotY1(YSelect.ItemIndex);
   If (Y2Select.ItemIndex > 0) then
        PlotY2(Y2Select.ItemIndex);
   If (Y3Select.ItemIndex > 0) then
        PlotY3(Y3Select.ItemIndex);
   If (Y4Select.ItemIndex > 0) then
        PlotY4(Y4Select.ItemIndex);
   If (Y5Select.ItemIndex > 0) then
        PlotY5(Y5Select.ItemIndex);
end;


procedure TSimulateForm.YSelectChange(Sender: TObject);
Var
   YVar : integer;
   X    : integer;            {titration point counter}

begin
   If (Not SimulationDone) then begin
       ShowMessage('You have no data to plot.');
       YSelect.Itemindex := 0;
      end;

   YVar := YSelect.ItemIndex;     {get the property from the combobox}

   If (YVar > 0) then begin      {it will be 0 if no property is selected}
     Series1.Title := YSelect.Items[YVar];
     If (LogMolar = 0) then begin
         LinearPlot;
         PlotAll;
       end                           {End If Logmolar = 0}
     Else PlotY1(YVar);

    end; {End if YVar > 0}

end;     {End YSelectChange}


procedure TSimulateForm.Y2SelectChange(Sender: TObject);
Var
   YVar : integer;
   X    : integer;            {titration point counter}

begin
   If (Not SimulationDone) then begin
       ShowMessage('You have no data to plot.');
       Y2Select.Itemindex := 0;
      end;

   YVar := Y2Select.ItemIndex;     {get the property from the combobox}

   If (YVar > 0) then begin      {it will be 0 if no property is selected}
     Series2.Title := Y2Select.Items[YVar];
     If (LogMolar = 0) then begin
         LinearPlot;
         PlotAll;
       end                           {End If Logmolar = 0}
     Else PlotY2(YVar);
     end;

end;     {End Y2SelectChange}

procedure TSimulateForm.Y3SelectChange(Sender: TObject);
Var
   YVar : integer;
   X    : integer;            {titration point counter}

begin
   If (Not SimulationDone) then begin
       ShowMessage('You have no data to plot.');
       Y3Select.Itemindex := 0;
      end;

   YVar := Y3Select.ItemIndex;     {get the property from the combobox}

   If (YVar > 0) then begin      {it will be 0 if no property is selected}
     Series3.Title := Y3Select.Items[YVar];
     If (LogMolar = 0) then begin
         LinearPlot;
         PlotAll;
       end                           {End If Logmolar = 0}
     Else PlotY3(YVar);
     end;
end;     {End Y3SelectChange}


procedure TSimulateForm.Y4SelectChange(Sender: TObject);
Var
   YVar : integer;
   X    : integer;            {titration point counter}

begin
    If (Not SimulationDone) then begin
       ShowMessage('You have no data to plot.');
       Y4Select.Itemindex := 0;
      end;

   YVar := Y4Select.ItemIndex;     {get the property from the combobox}

   If (YVar > 0) then begin      {it will be 0 if no property is selected}
     Series4.Title := Y4Select.Items[YVar];
     If (LogMolar = 0) then begin
         LinearPlot;
         PlotAll;
       end                           {End If Logmolar = 0}
     Else PlotY4(YVar);
     end;

end;     {End Y4SelectChange}

procedure TSimulateForm.Y5SelectChange(Sender: TObject);
Var
   YVar : integer;
   X    : integer;            {titration point counter}

begin
     If (Not SimulationDone) then begin
       ShowMessage('You have no data to plot.');
       Y5Select.Itemindex := 0;
      end;

   YVar := Y5Select.ItemIndex;     {get the property from the combobox}

   If (YVar > 0) then begin      {it will be 0 if no property is selected}
     Series5.Title := Y5Select.Items[YVar];
     If (LogMolar = 0) then begin
         LinearPlot;
         PlotAll;
       end                           {End If Logmolar = 0}
     Else PlotY5(YVar);
     end;

end;     {End Y5SelectChange}


procedure TSimulateForm.New1Click(Sender: TObject);
begin
   DefaultSimulation;
   ClearResults;
   WriteScreen;
end;

procedure TSimulateForm.MenuExitClick(Sender: TObject);
begin
   SimulateForm.Close;
end;

procedure TSimulateForm.About1Click(Sender: TObject);
begin
   ShowMessage('Titrator Chemical Equilibrium Calculator  v. 3.0 October 2008  SE Cabaniss');
end;

procedure TSimulateForm.TopicsClick(Sender: TObject);
begin
    HelpIndex := 7;
    TitrHelpForm.ShowModal;
end;

{LinearPlot determines the appropriate units (milli, micro, etc.) for }
{linear (Molar) plots. This number is YOrd, and is also used for scaling the }
{Y data in the plots.}

Procedure TSimulateForm.LinearPlot;
Var    TempMax : double;                {Temporary maximum value for an array}

begin

    {set the Y axis to use units of M, mM, uM, nM, etc.}

    {First find MaxYVal, the largest concentration in the set of 5 plotted}

         MaxYVal := GetAbMax(YData[YSelect.ItemIndex], SimuPts);
         If (Y2Select.ItemIndex > 0) then begin
            TempMax := GetAbMax(YData[Y2Select.ItemIndex], SimuPts);
            If (TempMax > MaxYVal) then MaxYVal := TempMax;
           end;
         If (Y3Select.ItemIndex > 0) then begin
            TempMax := GetAbMax(YData[Y3Select.ItemIndex], SimuPts);
            If (TempMax > MaxYVal) then MaxYVal := TempMax;
          end;
         If (Y4Select.ItemIndex > 0) then begin
            TempMax := GetAbMax(YData[Y4Select.ItemIndex], SimuPts);
            If (TempMax > MaxYVal) then MaxYVal := TempMax;
           end;
         If (Y5Select.ItemIndex > 0) then begin
            TempMax := GetAbMax(YData[Y5Select.ItemIndex], SimuPts);
            If (TempMax > MaxYVal) then MaxYVal := TempMax;
           end;

    {Now calculate Yord, the variable which indicates whether concentrations}
    {are mM, uM, nM, etc.}

         YOrd := -floor(ln(MaxYVal)/(LogConvr*3));
         If (YOrd > 6) then YOrd := 6;
         If (YOrd < 0) then YOrd := 0;

     SimulGraph.LeftAxis.Title.Caption := XUnit[YOrd] + 'olar';
end;                                     {End of LinearPlot}

{When the Log/Molar radio button is changed, LogMolClick gets the current status}
{  ItemIndex = 0  Molar concentration scale
{  ItemIndex = 1  Log Molar scale
{ If a molar scle is to be plotted, the data are scaled via the
{  procedure LinearPlot  }
{  Then all the data are replotted  }

procedure TSimulateForm.LogMolExit(Sender: TObject);
begin
   LogMolar := LogMol.ItemIndex;              {Get the scaling type}

   If (LogMolar = 0) then LinearPlot          {Re-scale data for molar plot}
      Else
       SimulGraph.LeftAxis.Title.Caption := 'Log Molar';

   PlotAll;                                 {re-plot the data}

end;

end.             {End of Simulate}
